using System;
using System.IO;

namespace OhioState.Graphics
{
    /// <summary>
    /// An auxiliary logging class with standard logging functionality.
    /// </summary>
    public sealed class gLogger
    {
        private static readonly gLogger instance = new gLogger();
        private static StreamWriter m_pFile = null;
        private int m_iIndent;
        private LogLevel m_iLogLevel;

        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static gLogger()
        {
        }

        private gLogger()
        {
            this.m_iIndent = 0;
            this.m_iLogLevel = 0;
        }
        /// <summary>
        /// Enumerates the types of log
        /// </summary>
        public enum LogTypes
        {
            /// <summary>
            /// Append the log
            /// </summary>
            LOG_APPEND = 1,
            /// <summary>
            /// Overwrite the log
            /// </summary>
            LOG_OVERWRITE = 2
        }

        /// <summary>
        /// Enumerates the levels of log
        /// </summary>
        public enum LogLevel
        {
            
            /// <summary>
            ///  Errors, or equivalent										        00001
            /// </summary>
            LEVEL_ONE = 1,   
            /// <summary>
            ///  Problems but recovered using default values (also prints 1)		00011
            /// </summary>
            LEVEL_TWO = 3,   
            /// <summary>
            ///  Prints enter/exit of functions (also prints 1 and 2)				00111
            /// </summary>
            LEVEL_THREE = 7, 
            /// <summary>
            ///  prints intermediate values (also prints 1 and 2)					01011
            /// </summary>
            LEVEL_FOUR = 11, 
            /// <summary>
            ///  prints everything! (prints 1-4)									11111
            /// </summary>
            LEVEL_FIVE = 31  
        }

        /// <summary>
        /// Get the static instance of the logger
        /// </summary>
        public static gLogger Instance
        {
            get
            {
                return instance;
            }
        }

        /// <summary>
        /// Open the log 
        /// </summary>
        /// <param name="pFile">filename to use for the log file</param>
        /// <param name="type">option append logfile or overwrite its contents if any</param>
        public void openLog(string pFile, LogTypes type)
        {
            m_pFile = new StreamWriter(pFile);
            if ((type & LogTypes.LOG_APPEND) != 0)
            {
                m_pFile = File.AppendText(pFile);
            }
            else if ((type & LogTypes.LOG_OVERWRITE) != 0 && pFile == null)
            {
                m_pFile = File.CreateText(pFile);
            }

            writeLog("/=============================================================================================\\\n");
            writeLog("=           Start of logging for the Volume Renderer: ");
            writeDate();
            writeTime();
            writeLog("\n");
            writeLog("=           Using loglevel: %i\n", m_iLogLevel);
            writeLog("\\=============================================================================================/\n");
        }

        /// <summary>
        /// Open the log 
        /// </summary>
        /// <param name="pFile">filename to use for the log file</param>
        /// <param name="type">option append logfile or overwrite its contents if any</param>
        /// <param name="level">log level to use.  This allows exclusion of different loggings and types.</param>
        public void openLog(string pFile, LogTypes type, LogLevel level)
        {
            this.m_iLogLevel = level;
            openLog(pFile, type);
        }


        
        /// <summary>
        /// closes the logging file 
        /// </summary>
        public void closeLog()
        {
            writeLog("/=============================================================================================\\\n");
            writeLog("=           Stopping logging for the Volume Renderer: ");
            writeDate();
            writeTime();
            writeLog("\n");
            writeLog("\\=============================================================================================/\n");

            m_pFile.Close();
        }

        /// <summary>
        /// Enter a function
        /// </summary>
        /// <param name="pFunctionName">function name</param>
        /// <param name="pFile">filename</param>
        /// <param name="iLine">linenumber</param>
        public void enterFunction(string pFunctionName, string pFile, int iLine)
        {
            if ((m_iLogLevel & LogLevel.LEVEL_THREE) != 0 || (m_iLogLevel & LogLevel.LEVEL_FIVE) != 0)
            {
                string contents = "Entered " + pFunctionName + " in " + pFile + " on " + iLine + "\n";
                writeLog(contents);
                m_iIndent += 1;
            }
        }
        /// <summary>
        /// Exit a function
        /// </summary>
        /// <param name="pFunctionName">function name</param>
        /// <param name="pFile">filename</param>
        /// <param name="iLine">linenumber</param>
        public void exitFunction(string pFunctionName, string pFile, int iLine)
        {
            if ((m_iLogLevel & LogLevel.LEVEL_THREE) != 0 || (m_iLogLevel & LogLevel.LEVEL_FIVE) != 0)
            {
                m_iIndent -= 1;
                string contents = "Exiting " + pFunctionName + " in " + pFile + " on " + iLine + "\n";
                writeLog(contents);
            }
        }

        /// <summary>
        /// Write date
        /// </summary>
        public void writeDate()
        {
            DateTime currentSystemTime = DateTime.Now;
            string contents = currentSystemTime.Month.ToString() + "." +
                              currentSystemTime.Day.ToString() + "." +
                              currentSystemTime.Year.ToString() + " ";
            for (int x = 0; x < m_iIndent; x++)
                writeLog(" ");

            writeLog(contents);
        }

        /// <summary>
        /// Write log
        /// </summary>
        /// <param name="pMessage">message to be written</param>
        public void writeLog(string pMessage)
        {
            if (m_pFile != null)
            {
                for (int x = 0; x < m_iIndent; x++)
                    writeLog(" ");
                m_pFile.Write(pMessage);
                m_pFile.Flush();
            }
        }

        /// <summary>
        /// Write log
        /// </summary>
        /// <param name="pMessage">message</param>
        /// <param name="level">log level</param>
        public void writeLog(string pMessage, LogLevel level)
        {
            if (m_pFile != null)
            {
                if ((this.m_iLogLevel & level) != 0)
                {
                    for (int x = 0; x < m_iIndent; x++)
                        writeLog(" ");
                    m_pFile.Write(pMessage);
                }
            }
        }

        /// <summary>
        /// Write time
        /// </summary>
        public void writeTime()
        {
            DateTime currentSystemTime = DateTime.Now;
            string contents = currentSystemTime.Hour.ToString() + ":" +
                              currentSystemTime.Minute.ToString() + ":" +
                              currentSystemTime.Second.ToString() + ":" +
                              currentSystemTime.Millisecond.ToString() + "\n";
            for (int x = 0; x < m_iIndent; x++)
                writeLog(" ");

            writeLog(contents);
        }

    }
}

